package android.slc.appbase.utils.process;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.system.SystemUtil;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class ProcessUtils {
    /**
     * 根据进程名称杀死旧的进程
     */
    public static void killOldPidByPName(String pName) {
        if (SystemUtil.getOsInfo().isWindows()) {
            try {
                Process process = RuntimeUtil.exec(System.getenv("windir") + "\\system32\\" + "tasklist.exe");
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line;
                String currentPid = String.valueOf(RuntimeUtil.getPid());
                while ((line = reader.readLine()) != null) {
                    Log.get().info("系统进程信息：{}", line);
                    List<String> processInfoList = StrUtil.split(line, " ");
                    CollectionUtil.filter(processInfoList, StrUtil::isNotBlank);
                    if (processInfoList.size() >= 2) {
                        if (StrUtil.contains(processInfoList.get(0), pName) && !StrUtil.equals(StrUtil.trim(processInfoList.get(1)), currentPid)) {
                            // 进程已经启动
                            String[] processInfo = line.split("\\s+");
                            String pid = processInfo[1];
                            String killProcessReturns = RuntimeUtil.execForStr("taskkill /F /PID " + pid);
                            Log.get().error("杀死旧进程结果：{}", killProcessReturns);
                        }
                    }
                }
            } catch (Exception e) {
                Log.get().error("查找并尝试结束进程失败：{}", e);
            }
        }
    }

    /**
     * 确保进程唯一
     */
    public static void insureProcessUnique() {
        try {
            Long processId = ProcessSp.getProcessId();
            if (processId != null) {
                killProcessByPid(processId);
            }
            ProcessSp.saveProcessId((long) RuntimeUtil.getPid());
        } catch (Throwable e) {
            Log.get().info("杀死进程错误：{}", e);
        }
    }

    public static void clearProcessInfo() {
        ProcessSp.saveProcessId(null);
    }

    /**
     * * 通过进程获进程id函数
     **/
    public static Long getPid(Process process) {
        long pid = 0L;
        try {
            if (process != null) {
                if (Platform.isWindows()) {
                    Field field = process.getClass().getDeclaredField("handle");
                    field.setAccessible(true);
                    long handler = field.getLong(process);
                    Kernel32 kernel = Kernel32.INSTANCE;
                    WinNT.HANDLE handle = new WinNT.HANDLE();
                    handle.setPointer(Pointer.createConstant(handler));
                    int ret = kernel.GetProcessId(handle);
                    pid = ret;
                } else if (Platform.isLinux() || Platform.isAIX()) {
                    Class<?> clazz = Class.forName("java.lang.UNIXProcess");
                    Field field = clazz.getDeclaredField("pid");
                    field.setAccessible(true);
                    pid = (Integer) field.get(process);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return pid;
    }

    /**
     * 关闭Linux进程
     *
     * @param pid 进程的PID
     */
    public static boolean killProcessByPid(Long pid) {
        if (pid == null || -1 == pid) {
            throw new RuntimeException("Pid ==" + pid);
        }
        Process process = null;
        BufferedReader reader = null;
        String command = "";
        boolean result;
        if (Platform.isWindows()) {
            command = "cmd.exe /c taskkill /PID " + pid + " /F /T ";
        } else if (Platform.isLinux() || Platform.isAIX()) {
            command = "kill -9 " + pid;
        }
        try {
            //杀掉进程
            process = Runtime.getRuntime().exec(command);
            reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
            String line = null;
            while ((line = reader.readLine()) != null) {
                Log.get().info("kill PID return info -----> " + line);
            }
            result = true;
        } catch (Exception e) {
            Log.get().info("杀进程出错：{}", e);
            result = false;
        } finally {
            if (process != null) {
                process.destroy();
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException ignored) {
                }
            }
        }
        return result;
    }

    /**
     * * 通过进程id判断是否被杀死.可以通过这个方法写守护进程
     **/
    public static boolean isAlive(Long pid) {
        Runtime runtime = Runtime.getRuntime();
        String queryCmd = "cmd /c tasklist|findstr " + pid;
        try {
            Process process = runtime.exec(queryCmd);
            //取得命令结果的输出流
            InputStream fis = process.getInputStream();
            //用一个读输出流类去读
            InputStreamReader isr = new InputStreamReader(fis);
            //用缓冲器读行
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            //直到读完为止
            if ((line = br.readLine()) != null) {
                if (line.contains("你的进程名")) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
